#include "RedisWrapper.h"
#include "LogManager.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <sstream>
#include <nlohmann/json.hpp>
#include <fmt/format.h>

namespace Market {

RedisWrapper::RedisWrapper(QObject* parent) : QObject(parent) {
    m_timer.setInterval(60000);  // 每分钟打印一次统计信息
    QObject::connect(&m_timer, &QTimer::timeout, this, &RedisWrapper::printStats);
    m_timer.start();
}

RedisWrapper::~RedisWrapper() {
    close();
}

bool RedisWrapper::init(const QString& configFile) {
    if (m_initialized) {
        MLOG_WARN("redis", "Redis already initialized");
        return true;
    }

    QFile file(configFile);
    if (!file.open(QIODevice::ReadOnly)) {
        MLOG_ERROR("redis", "Failed to open config file: {}", configFile.toStdString());
        return false;
    }

    QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
    file.close();

    if (doc.isNull() || !doc.isObject()) {
        MLOG_ERROR("redis", "Invalid JSON format in config file");
        return false;
    }

    QJsonObject config = doc.object();
    m_host = config["Host"].toString();
    m_port = config["Port"].toInt();
    m_password = config["Password"].toString();
    m_db = config["DB"].toInt();
    m_tickChannel = config["TickChannel"].toString("market.tick");
    m_barChannel = config["BarChannel"].toString("market.bar");

    if (!connect(m_host, m_port, m_password, m_db)) {
        return false;
    }

    m_initialized = true;
    MLOG_INFO("redis", "Redis initialized with {}:{}/{}", m_host.toStdString(), m_port, m_db);
    return true;
}

void RedisWrapper::close() {
    m_redis.reset();
    m_initialized = false;
    MLOG_INFO("redis", "Redis connection closed");
}

void RedisWrapper::publishTick(const WTSTickStruct& tick) {
    if (!m_redis) {
        MLOG_WARN("redis", "Redis not connected");
        return;
    }

    try {
        nlohmann::json json;
        json["code"] = tick.code;
        json["exchg"] = tick.exchg;
        json["price"] = tick.price;
        json["open"] = tick.open;
        json["high"] = tick.high;
        json["low"] = tick.low;
        json["preclose"] = tick.pre_close;
        json["total_volume"] = static_cast<int64_t>(tick.total_volume);
        json["volume"] = static_cast<int64_t>(tick.volume);
        json["total_turnover"] = tick.total_turnover;
        json["turnover"] = tick.turn_over;
        json["open_interest"] = tick.open_interest;
        json["diff_interest"] = tick.diff_interest;
        json["upper_limit"] = tick.upper_limit;
        json["lower_limit"] = tick.lower_limit;
        json["bid_price"] = tick.bid_prices[0];
        json["bid_qty"] = static_cast<int64_t>(tick.bid_qty[0]);
        json["ask_price"] = tick.ask_prices[0];
        json["ask_qty"] = static_cast<int64_t>(tick.ask_qty[0]);
        json["action_date"] = static_cast<int64_t>(tick.action_date);
        json["action_time"] = static_cast<int64_t>(tick.action_time);

        std::string key = fmt::format("tick:{}:{}", tick.exchg, tick.code);
        std::string message = json.dump();
        
        double score = static_cast<double>(tick.action_time);
        m_redis->zadd(key, message, score);
        m_redis->expire(key, 30 * 24 * 60 * 60);
        
        m_tickCount++;
        m_totalTicks++;
    } catch (const std::exception& e) {
        MLOG_ERROR("redis", "Failed to save tick data: {}", e.what());
        try {
            connect(m_host, m_port, m_password, m_db);
        } catch (const std::exception& e) {
            MLOG_ERROR("redis", "Failed to reconnect to Redis: {}", e.what());
        }
    }
}

void RedisWrapper::publishBar(const WTSBarStruct& bar, const std::string& exchg, 
                            const std::string& code, TrPeriod period) {
    if (!m_redis) {
        MLOG_WARN("redis", "Redis not connected");
        return;
    }

    try {
        nlohmann::json json;
        json["exchg"] = exchg;
        json["code"] = code;
        json["period"] = static_cast<int>(period);
        json["open"] = bar.open;
        json["high"] = bar.high;
        json["low"] = bar.low;
        json["close"] = bar.close;
        json["vol"] = static_cast<int64_t>(bar.vol);
        json["interest"] = static_cast<int64_t>(bar.interest);
        json["time"] = static_cast<int64_t>(bar.time);
        json["date"] = static_cast<int64_t>(bar.date);

        std::string key = fmt::format("{}:{}:{}", exchg, code, static_cast<int>(period));
        std::string message = json.dump();
        
        double score = static_cast<double>(bar.time);
        m_redis->zadd(key, message, score);
        m_redis->expire(key, 30 * 24 * 60 * 60);
        
        MLOG_DEBUG("redis", "Published bar data to Redis: key={}, time={}", 
            key, bar.time);
    } catch (const std::exception& e) {
        MLOG_ERROR("redis", "Failed to save bar data: {}", e.what());
    }
}

bool RedisWrapper::connect(const QString& host, uint16_t port, 
                         const QString& password, int db) {
    try {
        sw::redis::ConnectionOptions opts;
        opts.host = host.toStdString();
        opts.port = port;
        if (!password.isEmpty()) {
            opts.password = password.toStdString();
        }
        opts.db = db;
        
        m_redis = std::make_unique<sw::redis::Redis>(opts);
        m_redis->ping();
        
        MLOG_INFO("redis", "Connected to Redis server");
        return true;
    } catch (const std::exception& e) {
        MLOG_ERROR("redis", "Failed to connect to Redis: {}", e.what());
        m_redis.reset();
        return false;
    }
}

void RedisWrapper::printStats() {
    try {
        // 获取Redis内存使用情况
        auto info = m_redis->info("memory");
        std::string infoStr = info;
        
        // 解析info字符串，查找used_memory字段
        std::istringstream iss(infoStr);
        std::string line;
        int memoryUsage = 0;
        
        while (std::getline(iss, line)) {
            if (line.find("used_memory:") == 0) {
                // 提取used_memory的值
                auto pos = line.find(":");
                if (pos != std::string::npos) {
                    memoryUsage = std::stoi(line.substr(pos + 1));
                }
                break;
            }
        }
        
        // MLOG_INFO("redis", "Stats - Last minute: {} ticks, Total: {} ticks, Memory: {:.2f}MB ({} bytes)", 
        //     m_tickCount, m_totalTicks, static_cast<double>(memoryUsage) / (1024 * 1024), memoryUsage);
        
        m_tickCount = 0;  // 重置每分钟计数器
    }
    catch (const std::exception& e) {
        MLOG_ERROR("redis", "Failed to retrieve Redis memory info: {}", e.what());
    }
}

} // namespace Market